//================== K a l M a t r i x ==================
//Programmed by ZhaoYongwei@HUST(aeanswiftriver@gmail.com)
//24-Bit Bitmap Compression Algorithm
//A Curriculum Design for Data Structure Courses
//Started @2013/7/17
//Last Edited @2013/8/23
//=======================================================
//
//BMP file must have the header "BM" 0x4D42 and the KMF(KalMatrixFile) file must have the header "KM" 0x4D4B
//Returns:
//1     Success.
//0     Argument Not Found.
//-1    Unexpected File Header.
//-2    Unexpected Color Depth. 24Bit Depth Accept Only.
//-3    Memory Overflow.
//-4    Image Size Not Equal.

#define _MT
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <windows.h>
#include <time.h>
#include <pthread.h>
#define max(a,b) ((a)>(b)?(a):(b));

BITMAPFILEHEADER fileHeader;
BITMAPINFOHEADER infoHeader;
FILE* pfout;
FILE* pfin;
clock_t tstamp1, tstamp2, tstamp3, tstamp4;
int finished, total;
int quality;
int lastprogress=-1;
int lastprogress2=-1;
int maxdepth;
int bmpcomp( void );
int decomp( void );
void refreshprogress( void );
void analyse( int, int );
void* drawnode( void* );

#pragma pack(1) //Fixed Memory Align Coeff.
typedef struct {
    BYTE b;
    BYTE g;
    BYTE r;
} QRGB;
QRGB **img;
char **openform;
typedef struct {
    int depth;
    QRGB color;
} QT;
int* nodefinding;
typedef struct {
    QT* elem;
    int length;
    int listsize;
} SqList;
SqList list;
#pragma pack(4)

void* BMQT( void* );

//Structure for multithreads.
SqList SL1, SL2, SL3, SL4;
int finicore[4];
int coredepth[4];
typedef struct {
    int l;
    int t;
    int width;
    int height;
    int depth;
    int core;
    SqList* SL;
} arg;
pthread_t thread[4];
pthread_attr_t attr;
pthread_cond_t notfull=PTHREAD_COND_INITIALIZER;
pthread_cond_t notempty=PTHREAD_COND_INITIALIZER;
pthread_cond_t notemptyout=PTHREAD_COND_INITIALIZER;
pthread_mutex_t mut;
pthread_mutex_t mutcw=PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t mutbk=PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t mutot=PTHREAD_MUTEX_INITIALIZER;
void* counter( void* );

//Structure for haff
int offs=0, offs2=0, offs3=0;
unsigned char* buffer;
unsigned char* bufout;
typedef struct ENode {
    unsigned char symbol;
    int frequency;
    char code[256];
    int lvl;
    bool flag;
    ENode* p;
    ENode* l;
    ENode* r;
} ENode;
ENode e[512],*max;
void haffcomp( void );
void haffdecode( void );
void coding( ENode*, int );
void* bufread( void* );
void* bufconsume( void* );
void* bufcode( void* );
void* bufwrite( void* );
void* bufwrite2( void* );
void* bufdecode( void* );


void coding( ENode* n, int lvl ) {
    n->lvl=lvl;
    if (n->l!=NULL) {
        for (int i=0; i<=lvl; i++) {
            n->l->code[i]=n->code[i];
        }
        n->l->code[lvl+1]=0;
        coding( n->l, lvl+1 );
    }
    if (n->r!=NULL) {
        for (int i=0; i<=lvl; i++) {
            n->r->code[i]=n->code[i];
        }
        n->r->code[lvl+1]=1;
        coding( n->r, lvl+1 );
    }
}
void* bufconsume( void* ch ) {
    unsigned char b;
    int o=0;
    do {
        pthread_mutex_lock(&mut);
        if (o==offs) pthread_cond_wait(&notempty,&mut);
        else pthread_mutex_unlock(&mut);
        b=buffer[o++];
        e[b].frequency++;
        finicore[0]++;
    } while(o<total);
    return ch;
}
void* bufread( void* ch ) {
    offs=0;
    do {
        fread(&buffer[offs],4096,1,pfin);
        offs+=4096;
        pthread_cond_signal(&notempty);
        pthread_mutex_unlock(&mut);
    } while(!feof(pfin));
    return ch;
}
void* bufdecode( void* ch ) {
    unsigned char b;
    int b2, count=0;
    ENode *pe;
    pe=&e[510];
    finicore[0]=0;
    do {
        pthread_mutex_lock(&mut);
        if (offs3==offs) pthread_cond_wait(&notempty,&mut);
        else pthread_mutex_unlock(&mut);
        b=buffer[offs3++];
        for (count=7; count>=0; count--) {
            b2=(b>>count)&1;
            if (b2==0) {
                //l
                pe=pe->l;
                if (pe->l==NULL||pe->r==NULL) {
                    pthread_mutex_lock(&mutcw);
                    if (offs2>=16383) {
                        pthread_mutex_lock(&mutbk);
                        pthread_mutex_unlock(&mutcw);
                        pthread_cond_wait(&notfull,&mutbk);
                        pthread_mutex_lock(&mutcw);
                    }
                    memcpy( &bufout[offs2++] ,&pe->symbol, 1);
                    if (offs2>=4096) {
                        pthread_cond_signal(&notemptyout);
                        pthread_mutex_unlock(&mutcw);
                        pthread_mutex_unlock(&mutbk);
                    } else pthread_mutex_unlock(&mutcw);
                    pe=&e[510];
                    finished++;
                }
            } else {
                //r
                pe=pe->r;
                if (pe->l==NULL||pe->r==NULL) {
                    pthread_mutex_lock(&mutcw);
                    if (offs2>=16383) {
                        pthread_mutex_lock(&mutbk);
                        pthread_mutex_unlock(&mutcw);
                        pthread_cond_wait(&notfull,&mutbk);
                        pthread_mutex_lock(&mutcw);
                    }
                    memcpy( &bufout[offs2++] ,&pe->symbol, 1);
                    if (offs2>=4096) {
                        pthread_cond_signal(&notemptyout);
                        pthread_mutex_unlock(&mutcw);
                        pthread_mutex_unlock(&mutbk);
                    } else pthread_mutex_unlock(&mutcw);
                    pe=&e[510];
                    finished++;
                }
            }
        }
    } while(finished<total);
    pthread_cond_signal(&notemptyout);
    pthread_mutex_unlock(&mutcw);
    pthread_mutex_unlock(&mutbk);
    return ch;
}

void* bufwrite2(void* ch) {
    do {
        if (offs2>=4096) {
            fwrite( bufout, 4096, 1, pfout );
            pthread_mutex_lock(&mutcw);
            offs2-=4096;
            memmove( bufout, &bufout[4096], offs2 );
            pthread_cond_signal(&notfull);
            pthread_mutex_unlock(&mutcw);
            pthread_mutex_unlock(&mutbk);
        } else {
            pthread_mutex_lock(&mutbk);
            pthread_cond_wait(&notemptyout,&mutbk);
        }
    } while(finished<total);
    fwrite( bufout, offs2, 1, pfout );
    offs2=0;
    return ch;
}

void haffcomp( void ) {
    int i, count;
    max=&e[511];
    printf("Scanning for frequency...   \n");
    finished=0;
    offs=0;
    finicore[0]=0;
    finicore[1]=0;
    finicore[2]=0;
    finicore[3]=0;
    buffer=(unsigned char *)malloc(sizeof(unsigned char)*(total+4));
    if (!buffer) {
        printf( "\nInsufficient memory space.\nKalMatrix stopped.\n" );
        exit(-3);
    }
    pthread_mutex_init(&mut,NULL);
    pthread_attr_init(&attr);
    pthread_attr_setschedpolicy(&attr, SCHED_FIFO);//sched_policy
    pthread_create( &thread[0], &attr, &bufconsume, NULL );
    pthread_create( &thread[1], &attr, &bufread, NULL );
    pthread_t threadcounter;
    pthread_create( &threadcounter, &attr, &counter, NULL );
    while (pthread_kill(thread[0],0)==0||pthread_kill(thread[1],0)==0) {
        pthread_join(thread[0],NULL);
        pthread_join(thread[1],NULL);
    }
    pthread_cancel(threadcounter);
    finished=total;
    refreshprogress();
    for (i=0; i<256; i++) {
        e[i].symbol=(unsigned char)i;
        e[i].p=NULL;
        e[i].flag=FALSE;
        fwrite( &e[i].frequency, sizeof(e[i].frequency), 1, pfout );
    }
    printf("   OK\nCoding entropy....   ");
    count=256;
    while(1) {
        int maxf=-1;
        int maxi=-1;
        int maxj=-1;
        int max2f=-1;
        for (i=0; i<count; i++) {
            if (e[i].flag==TRUE) continue;
            if (maxf>=e[i].frequency||maxf==-1) {
                if(max2f>=maxf||max2f==-1) {
                    maxj=maxi;
                    max2f=maxf;
                }
                maxi=i;
                maxf=e[i].frequency;
            }
            if((max2f>=e[i].frequency||max2f==-1)&&maxi!=i) {
                maxj=i;
                max2f=e[i].frequency;
            }
        }
        if (maxj==-1) break;
        e[maxi].p=&e[count];
        e[count].l=&e[maxi];
        e[count].r=&e[maxj];
        e[maxj].p=&e[count];
        e[count].frequency=e[maxi].frequency+e[maxj].frequency;
        e[count].flag=FALSE;
        e[maxi].flag=TRUE;
        e[maxj].flag=TRUE;
        max=&e[count];
        count++;
    }
    max->code[0]=0;
    //Notify: code start from code[1]. for(i=1;i<=lvl;i++).
    coding( max, 0 );
    //FILE* tree = fopen( "tree.txt", "w" );
    //for (i=0;i<256;i++) {fprintf(tree,"\n%d-%d: ",i,e[i].frequency);for(count=1;count<=e[i].lvl;count++) fprintf(tree,"%d", (e[i].code[count]==0)?0:1);}
    //fclose(tree);
    printf("OK\nHaffman Coding...(2 of 2)\n");
    bufout=(unsigned char *)malloc(sizeof(unsigned char)*16384);
    if (!bufout) {
        printf( "\nInsufficient memory space.\nKalMatrix stopped.\n" );
        exit(-3);
    }
    finished=0;
    count=0;
    offs=0;
    pthread_mutex_init(&mut,NULL);
    pthread_attr_init(&attr);
    pthread_attr_setschedpolicy(&attr, SCHED_FIFO);//sched_policy
    pthread_create( &thread[0], &attr, &bufcode, NULL );
    pthread_create( &thread[1], &attr, &bufwrite, NULL );
    pthread_create( &threadcounter, &attr, &counter, NULL );
    while (pthread_kill(thread[0],0)==0||pthread_kill(thread[1],0)==0) {
        pthread_join(thread[0],NULL);
        pthread_join(thread[1],NULL);
    }
    pthread_cancel(threadcounter);
    finished=total;
    refreshprogress();
    return;
}

void* bufcode( void* ch ) {
    unsigned char b;
    int i, count=0, b2=0;
    finicore[0]=0;
    do {
        b=buffer[finicore[0]++];
        for ( i=1; i<=e[b].lvl; i++ ) {
            b2=(b2<<1)+e[b].code[i];
            count++;
            if (count==8) {
                count=0;
                pthread_mutex_lock(&mutcw);
                if (offs>=16383) {
                    pthread_mutex_lock(&mut);
                    pthread_mutex_unlock(&mutcw);
                    pthread_cond_wait(&notfull,&mut);
                    pthread_mutex_lock(&mutcw);
                }
                memcpy( &bufout[offs++], &b2, 1 );
                if (offs>=4096) {
                    pthread_cond_signal(&notempty);
                    pthread_mutex_unlock(&mutcw);
                    pthread_mutex_unlock(&mut);
                } else pthread_mutex_unlock(&mutcw);
                b2=0;
            }
        }
    } while(finicore[0]<total);
    if (count>0) {
        b2=b2<<(8-count);
        pthread_mutex_lock(&mutcw);
        if (offs>=16383) {
            pthread_mutex_lock(&mut);
            pthread_mutex_unlock(&mutcw);
            pthread_cond_wait(&notfull,&mut);
            pthread_mutex_lock(&mutcw);
        }
        memcpy( &bufout[offs++], &b2, 1 );
        pthread_cond_signal(&notempty);
        pthread_mutex_unlock(&mutcw);
        pthread_mutex_unlock(&mutbk);
    }
    return ch;
}

void* bufwrite(void* ch) {
    do {
        if (offs>=4096) {
            fwrite( bufout, 4096, 1, pfout );
            pthread_mutex_lock(&mutcw);
            offs-=4096;
            memmove( bufout, &bufout[4096], offs );
            pthread_cond_signal(&notfull);
            pthread_mutex_unlock(&mutcw);
            pthread_mutex_unlock(&mut);
        } else {
            pthread_mutex_lock(&mut);
            pthread_cond_wait(&notempty,&mut);
        }
    } while(finicore[0]<total);
    if (offs>=16383) {
        pthread_mutex_lock(&mutcw);
        fwrite( bufout, offs, 1, pfout );
        offs=0;
        pthread_mutex_unlock(&mutcw);
        pthread_cond_signal(&notfull);
        pthread_mutex_unlock(&mut);
        pthread_mutex_lock(&mutbk);
        pthread_cond_wait(&notempty,&mutbk);
    }
    fwrite( bufout, offs, 1, pfout );
    offs=0;
    return ch;
}


void haffdecode( void ) {
    int i, count;
    max=&e[511];
    printf("Scanning for frequency...   ");
    for (i=0; i<256; i++) {
        fread( &e[i].frequency, sizeof(e[i].frequency), 1, pfin );
        e[i].symbol=(unsigned char)i;
        e[i].flag=FALSE;
        e[i].p=NULL;
    }
    printf("OK\nCoding entropy....   ");
    count=256;
    while(1) {
        int maxf=-1;
        int maxi=-1;
        int maxj=-1;
        int max2f=-1;
        for (i=0; i<count; i++) {
            if (e[i].flag==TRUE) continue;
            if (maxf>=e[i].frequency||maxf==-1) {
                if(max2f>=maxf||max2f==-1) {
                    maxj=maxi;
                    max2f=maxf;
                }
                maxi=i;
                maxf=e[i].frequency;
            }
            if((max2f>=e[i].frequency||max2f==-1)&&maxi!=i) {
                maxj=i;
                max2f=e[i].frequency;
            }
        }
        if (maxj==-1) break;
        e[maxi].p=&e[count];
        e[count].l=&e[maxi];
        e[count].r=&e[maxj];
        e[maxj].p=&e[count];
        e[count].frequency=e[maxi].frequency+e[maxj].frequency;
        e[count].flag=FALSE;
        e[maxi].flag=TRUE;
        e[maxj].flag=TRUE;
        max=&e[count];
        count++;
    }
    max->code[0]=0;
    //Notify: code start from code[1]. for(i=1;i<=lvl;i++).
    coding( max, 0 );
    printf("OK\nHaffman Decoding...(1 of 2)\n");
    buffer=(unsigned char *)malloc(sizeof(unsigned char)*(total+4));
    if (!buffer) {
        printf( "\nInsufficient memory space.\nKalMatrix stopped.\n" );
        exit(-3);
    }
    bufout=(unsigned char *)malloc(sizeof(unsigned char)*16384);
    if (!bufout) {
        printf( "\nInsufficient memory space.\nKalMatrix stopped.\n" );
        exit(-3);
    }
    pthread_mutex_init(&mut,NULL);
    pthread_attr_init(&attr);
    pthread_attr_setschedpolicy(&attr, SCHED_FIFO);//sched_policy
    pthread_create( &thread[0], &attr, &bufread, NULL );
    pthread_create( &thread[1], &attr, &bufwrite2, NULL );
    pthread_create( &thread[2], &attr, &bufdecode, NULL );
    pthread_t threadcounter;
    pthread_create( &threadcounter, &attr, &counter, NULL );
    while (pthread_kill(thread[0],0)==0||pthread_kill(thread[1],0)==0||pthread_kill(thread[2],0)==0) {
        pthread_join(thread[0],NULL);
        pthread_join(thread[1],NULL);
        pthread_join(thread[2],NULL);
    }
    pthread_cancel(threadcounter);
    finished=total;
    refreshprogress();
    printf("\n");
    return;
}


int main( int argc, char* argv[] ) {
    printf( "================== K a l M a t r i x ==================\n" );
    printf( "24-Bit Bitmap Compression Algorithm\n" );
    printf( "A Curriculum Design for Data Structure Courses\n" );
    printf( "Copyright 2013 ZhaoYongwei@HUST(aeanswiftriver@gmail.com)\n" );
    printf( "=======================================================\n" );
    printf( "Version: Release 6 Revision 78\nVisit kalmatrix.googlecode.com for bug reporting and suggestions.\n" );
    printf( "\n" );
    if ( argc==1 ) {
        printf( "Compress/Decompress Syntax:\n" );
        printf( "KalMatrix source [quality]\n\n" );
        printf( "source  -  The filename of source file with vaild path. BMP or KMF accepted.\n" );
        printf( "quality -  Used in compressing. Integer between 0~100, the larger number means\n           better quality and bigger file.\n" );
        printf( "           Default : 100\n\n" );
        printf( "PSNR Analyse Syntax:\n" );
        printf( "KalMatrix -a source1 source2\n\n" );
        printf( "source  -  The filename with vaild path of the files you want to analyse.\n" );
        return 0;
    }
    if ( strcmp( argv[1], "-a" )==0 || strcmp( argv[1], "-A" )==0 ) {
        printf( "*** Analyse Mode ***\n" );
        if ( argc!=4 ) {
            printf( "Too few or too many arguments for the analyse mode.\nKalMatrix stopped." );
            return 0;
        }
        pfin =fopen( argv[2], "rb" );
        pfout =fopen( argv[3], "rb" );
        if (pfin==NULL||pfout==NULL) {
            printf("Cannot open the source file.\nKalMatrix stopped.");
            return -1;
        }
        fread( &fileHeader, sizeof( BITMAPFILEHEADER ), 1, pfin );
        if (fileHeader.bfType!=0x4D42) {
            printf("Unexpected file 1 header.\nKalMatrix stopped.");
            return -1;
        }
        fread( &fileHeader, sizeof( BITMAPFILEHEADER ), 1, pfout );
        if (fileHeader.bfType!=0x4D42) {
            printf("Unexpected file 2 header.\nKalMatrix stopped.");
            return -1;
        }
        BITMAPINFOHEADER ih1, ih2;
        fread( &ih1, sizeof( BITMAPINFOHEADER ), 1, pfin );
        fread( &ih2, sizeof( BITMAPINFOHEADER ), 1, pfout );
        if ( ih1.biWidth!=ih2.biWidth || ih1.biHeight!=ih2.biHeight ) {
            printf("Image Size Not Equal.\nKalMatrix stopped.");
            return -4;
        }
        if ( ih1.biBitCount!=24 || ih2.biBitCount!=24 ) {
            printf( "Wrong Depth. KalMatrix only accept 24Bit Depth.\nKalMatrix stopped.\n" );
            return -2;
        }
        analyse( ih1.biWidth, ih1.biHeight );
        return 1;
    }
    pfin =fopen( argv[1], "rb" );
    char s[255], *p, s2[255], *p2;
    strcpy( s, argv[1] );
    strcpy( s2, argv[1] );
    p2=s2;
    p=s;
    //Read the Bitmap file header;
    fread( &fileHeader, sizeof( BITMAPFILEHEADER ), 1, pfin );
    if ( fileHeader.bfType==0x4D42 ) {
        printf( "BMP Detected.\n" );
        strcat( p, ".tmp" );
        pfout=fopen( p, "wb+" );
        quality=argc==3?atoi( argv[2] ):100;
        int compret=bmpcomp();
        if (compret<0) return compret;
        strcat( p2, ".kmf" );
        printf( "Clear memory. Prepare to calculate entropy.\n" );
        fclose(pfin);
        pfin=pfout;
        pfout=fopen( p2, "wb" );
        fseek(pfin,0,SEEK_END);
        total=ftell(pfin);
        fseek(pfin,0,SEEK_SET);
        fread( &fileHeader.bfType, sizeof( fileHeader.bfType ), 1, pfin );
        fwrite( &fileHeader.bfType, sizeof( fileHeader.bfType ), 1, pfout );
        fwrite( &total, sizeof( total ), 1, pfout );
        tstamp3=clock();
        haffcomp();
        tstamp4=clock();
        double dur1=(double)( tstamp4-tstamp3 )/CLOCKS_PER_SEC;
        printf( "\n%d Bytes Coded in %.3fsec.\n", total, dur1 );
        printf( "Entropy Compression Complete.\nKalMatrix stopped in %.3fsec.\n", (double)clock()/CLOCKS_PER_SEC );
        fclose( pfin );
        fclose( pfout );
        remove( p );
        return compret;
    } else if( fileHeader.bfType==0x4D4B ) {
        printf( "Matrix Detected.\n" );
        strcat( p, ".tmp" );
        pfout=fopen( p, "wb+" );
        fseek(pfin,0,SEEK_SET);
        fread( &fileHeader.bfType, sizeof( fileHeader.bfType ), 1, pfin );
        fread( &total, sizeof( total ), 1, pfin );
        fwrite( &fileHeader.bfType, sizeof( fileHeader.bfType ), 1, pfout );
        tstamp3=clock();
        haffdecode();
        tstamp4=clock();
        double dur1=(double)( tstamp4-tstamp3 )/CLOCKS_PER_SEC;
        printf( "%d Bytes Decoded in %.3fsec.\n", total, dur1 );
        fclose( pfin );
        pfin = pfout;
        rewind(pfin);
        strcat( p2, ".bmp" );
        printf( "Clear memory. Prepare to calculate QT.\n" );
        //memclear;
        pfout=fopen( p2, "wb" );
        fread( &fileHeader, sizeof( BITMAPFILEHEADER ), 1, pfin );
        int decompret=decomp();
        fclose(pfin);
        fclose(pfout);
        remove( p );
        return decompret;
    } else {
        printf( "Unexpected file header. This file may have been damaged.\nKalMatrix stopped.\n" );
        return -1;
    }
    printf( "\n" );
}

void analyse( int width, int height ) {
    double mse=0;
    double psnr;
    QRGB a,b;
    total=width*height;
    for (int i=0; i<width; i++) {
        for (int j=0; j<height; j++) {
            fread(&a,sizeof(QRGB),1,pfin);
            fread(&b,sizeof(QRGB),1,pfout);
            mse+=pow((a.b-b.b),2)+pow((a.g-b.g),2)+pow((a.r-b.r),2);
            finished++;
        }
        refreshprogress();
    }
    printf("\n");
    if (mse==0) {
        printf("MSE = 0, PSNR = Infinite.\nKalMatrix stopped.");
        return;
    }
    mse/=3;
    mse/=total;
    psnr=10*log(65025/mse);
    printf("MSE = %.3lf, PSNR = %.4lf dB.\nKalMatrix stopped.",mse,psnr);
    return;
}

int decomp( void ) {
    //Read info header.
    fread( &infoHeader, sizeof( BITMAPINFOHEADER ), 1, pfin );
    //int size = infoHeader.biWidth*infoHeader.biHeight;
    int width=infoHeader.biWidth;
    int height=infoHeader.biHeight;
    int i, j;
    img=(QRGB**)malloc( sizeof( QRGB* )*height );
    for ( i=0; i<height; i++ ) {
        img[i]=(QRGB*)malloc( sizeof( QRGB )*width );
        if ( !img[i] ) {
            printf( "\nInsufficient memory space.\nKalMatrix stopped.\n" );
            return -3;
        }
    }
    openform=(char**)malloc( sizeof( char* )*height );
    for ( i=0; i<height; i++ ) {
        openform[i]=(char*)malloc( sizeof( char )*width );
        if ( !openform[i] ) {
            printf( "\nInsufficient memory space.\nKalMatrix stopped.\n" );
            return -3;
        }
        memset(openform[i],0,sizeof( char )*width);
    }
    fread( &list.length, sizeof( list.length ), 1, pfin );
    list.elem=(QT*)malloc( ( list.length+1 )*sizeof( QT ) );
    if ( !list.elem ) {
        printf( "\nInsufficient memory space.\nKalMatrix stopped.\n" );
        return -3;
    }
    list.listsize=list.length+1;
    //read QT Nodes.
    fread( list.elem, sizeof( QT ), list.length, pfin );
    //Decompressing start.
    printf( "Decompressing Start. \nQuad-tree Algorithm Calculating...(2 of 2)\n" );
    tstamp1=clock();
    maxdepth=-2;
    for ( i=0; i<list.length; i++ ) {
        maxdepth=max( list.elem[i].depth, maxdepth );
    }
    nodefinding=(int*)malloc( ( maxdepth+2 )*sizeof( int ) );
    if ( !nodefinding ) {
        printf( "\nInsufficient memory space.\nKalMatrix stopped.\n" );
        return -3;
    }
    memset(nodefinding,0xff, ( maxdepth+2 )*sizeof( int ) );
    for ( i=0; i<list.length; i++ ) {
        nodefinding[list.elem[i].depth+1]=i;
    }
    total=width*height;
    finished=0;
    memset(finicore,0,4*sizeof(int));
    pthread_mutex_init(&mut,NULL);
//    if ( total>0x1000000 ){
//        tstate=1;
    pthread_attr_init(&attr);
    pthread_attr_setschedpolicy(&attr, SCHED_FIFO);//sched_policy
    arg arg1, arg2, arg3, arg4;
    coredepth[0]=0;
    coredepth[1]=1;
    coredepth[2]=2;
    coredepth[3]=3;
    arg1.l=0;
    arg1.t=0;
    arg1.width=width>>1;
    arg1.height=height>>1;
    arg1.depth=0;
    arg1.core=0;
    pthread_create( &thread[0], &attr, &drawnode, (void*)&arg1 );
    arg2.l=width>>1;
    arg2.t=0;
    arg2.width=width-(width>>1);
    arg2.height=height>>1;
    arg2.depth=1;
    arg2.core=1;
    pthread_create( &thread[1], &attr, &drawnode, (void*)&arg2 );
    arg3.l=0;
    arg3.t=height>>1;
    arg3.width=width>>1;
    arg3.height=height-(height>>1);
    arg3.depth=2;
    arg3.core=2;
    pthread_create( &thread[2], &attr, &drawnode, (void*)&arg3 );
    arg4.l=width>>1;
    arg4.t=height>>1;
    arg4.width=width-(width>>1);
    arg4.height=height-(height>>1);
    arg4.depth=3;
    arg4.core=3;
    pthread_create( &thread[3], &attr, &drawnode, (void*)&arg4 );
//        drawnode( (void*)&arg4 );
    pthread_t threadcounter;
    pthread_create( &threadcounter, &attr, &counter, NULL );
    while (pthread_kill(thread[0],0)==0||pthread_kill(thread[1],0)==0||pthread_kill(thread[2],0)==0||pthread_kill(thread[3],0)==0) {
        pthread_join(thread[0],NULL);
        pthread_join(thread[1],NULL);
        pthread_join(thread[2],NULL);
        pthread_join(thread[3],NULL);
    }
    pthread_cancel(threadcounter);
    clock_t tstamph=clock();
    free(nodefinding);
    finished=finicore[0]+finicore[1]+finicore[2]+finicore[3];
    for ( i=0; i<height; i++ ) {
        for ( j=0; j<width; j++ ) {
            if ( openform[i][j]==0 ) {
                fread( &img[i][j], sizeof( QRGB ), 1, pfin );
                finished++;
            }
        }
        refreshprogress();
    }
    tstamp2=clock();
    double dur1=(double)( tstamp2-tstamp1 )/CLOCKS_PER_SEC;
    double dur2=(double)( tstamph-tstamp1 )/CLOCKS_PER_SEC;
    printf( "\n" );
    printf( "%d Nodes Calculated in %.3fsec. %.3fsec elapsed in this phase.\n", list.length, dur2, dur1 );
    //Write in file.
    printf( "Writing Bitmap Into File..." );
    fileHeader.bfType=0x4D42; //Write Header BM
    fwrite( &fileHeader, sizeof( fileHeader ), 1, pfout );
    fwrite( &infoHeader, sizeof( infoHeader ), 1, pfout );
    for ( i=0; i<height; i++ )
        fwrite( img[i], sizeof( QRGB ), width, pfout );
    printf( "    OK\nDeompression Success.\nKalMatrix stopped in %.3fsec.\n", (double)clock()/CLOCKS_PER_SEC );
    return 1;
}

//new drawnode(): find node according to depth. not to the index of SqList.
void* drawnode( void* ch ) {
    arg* voidarg = (arg*)ch;
    int t=voidarg->t;
    int l=voidarg->l;
    int depth=voidarg->depth;
    int h=voidarg->height;
    int w=voidarg->width;
    int core=voidarg->core;
    int size=h*w;
    if ( size<=2 ) return NULL;
    if ( t<0 || l<0 || t+h>infoHeader.biHeight || l+w>infoHeader.biWidth ) return NULL;
    if ( depth>maxdepth ) return NULL;
    if ( nodefinding[depth+1]==-1 ) {
        int hh=h>>1;
        int hw=w>>1;
        int nd=( depth+1 )<<2;
        arg arg1, arg2, arg3, arg4;
        if (size>=8388608) {
            if (pthread_mutex_trylock(&mut)==0) {
                if (pthread_kill(thread[0],0)==0) {
                    pthread_mutex_unlock(&mut);
                    arg1.l=l;
                    arg1.t=t;
                    arg1.width=hw;
                    arg1.height=hh;
                    arg1.depth=nd;
                    arg1.core=core;
                    drawnode( (void*)&arg1 );
                } else {
                    arg1.l=l;
                    arg1.t=t;
                    arg1.width=hw;
                    arg1.height=hh;
                    arg1.depth=nd;
                    arg1.core=0;
                    coredepth[0]=arg1.depth;
                    pthread_create( &thread[0], &attr, &drawnode, (void*)&arg1 );
                    pthread_mutex_unlock(&mut);
                }
            } else {
                arg1.l=l;
                arg1.t=t;
                arg1.width=hw;
                arg1.height=hh;
                arg1.depth=nd;
                arg1.core=core;
                drawnode( (void*)&arg1 );
            }
            if (pthread_mutex_trylock(&mut)==0) {
                if (pthread_kill(thread[1],0)==0) {
                    pthread_mutex_unlock(&mut);
                    arg2.l=l+hw;
                    arg2.t=t;
                    arg2.width=w-hw;
                    arg2.height=hh;
                    arg2.depth=nd+1;
                    arg2.core=core;
                    drawnode( (void*)&arg2 );
                } else {
                    arg2.l=l+hw;
                    arg2.t=t;
                    arg2.width=w-hw;
                    arg2.height=hh;
                    arg2.depth=nd+1;
                    arg2.core=1;
                    coredepth[1]=arg2.depth;
                    pthread_create( &thread[1], &attr, &drawnode, (void*)&arg2 );
                    pthread_mutex_unlock(&mut);
                }
            } else {
                arg2.l=l+hw;
                arg2.t=t;
                arg2.width=w-hw;
                arg2.height=hh;
                arg2.depth=nd+1;
                arg2.core=core;
                drawnode( (void*)&arg2 );
            }
            if (pthread_mutex_trylock(&mut)==0) {
                if (pthread_kill(thread[2],0)==0) {
                    pthread_mutex_unlock(&mut);
                    arg3.l=l;
                    arg3.t=t+hh;
                    arg3.width=hw;
                    arg3.height=h-hh;
                    arg3.depth=nd+2;
                    arg3.core=core;
                    drawnode( (void*)&arg3 );
                } else {
                    arg3.l=l;
                    arg3.t=t+hh;
                    arg3.width=hw;
                    arg3.height=h-hh;
                    arg3.depth=nd+2;
                    arg3.core=2;
                    coredepth[2]=arg3.depth;
                    pthread_create( &thread[2], &attr, &drawnode, (void*)&arg3 );
                    pthread_mutex_unlock(&mut);
                }
            } else {
                arg3.l=l;
                arg3.t=t+hh;
                arg3.width=hw;
                arg3.height=h-hh;
                arg3.depth=nd+2;
                arg3.core=core;
                drawnode( (void*)&arg3 );
            }
            if (pthread_mutex_trylock(&mut)==0) {
                if (pthread_kill(thread[3],0)==0) {
                    pthread_mutex_unlock(&mut);
                    arg4.l=l+hw;
                    arg4.t=t+hh;
                    arg4.width=w-hw;
                    arg4.height=h-hh;
                    arg4.depth=nd+3;
                    arg4.core=core;
                    drawnode( (void*)&arg4 );
                } else {
                    arg4.l=l+hw;
                    arg4.t=t+hh;
                    arg4.width=w-hw;
                    arg4.height=h-hh;
                    arg4.depth=nd+3;
                    arg4.core=3;
                    coredepth[3]=arg4.depth;
                    pthread_create( &thread[3], &attr, &drawnode, (void*)&arg4 );
                    pthread_mutex_unlock(&mut);
                }
            } else {
                arg4.l=l+hw;
                arg4.t=t+hh;
                arg4.width=w-hw;
                arg4.height=h-hh;
                arg4.depth=nd+3;
                arg4.core=core;
                drawnode( (void*)&arg4 );
            }
        } else {
            arg1.l=l;
            arg1.t=t;
            arg1.width=hw;
            arg1.height=hh;
            arg1.depth=nd;
            arg1.core=core;
            drawnode( (void*)&arg1 );
            arg2.l=l+hw;
            arg2.t=t;
            arg2.width=w-hw;
            arg2.height=hh;
            arg2.depth=nd+1;
            arg2.core=core;
            drawnode( (void*)&arg2 );
            arg3.l=l;
            arg3.t=t+hh;
            arg3.width=hw;
            arg3.height=h-hh;
            arg3.depth=nd+2;
            arg3.core=core;
            drawnode( (void*)&arg3 );
            arg4.l=l+hw;
            arg4.t=t+hh;
            arg4.width=w-hw;
            arg4.height=h-hh;
            arg4.depth=nd+3;
            arg4.core=core;
            drawnode( (void*)&arg4 );
        }
    } else {
        QT node = list.elem[nodefinding[depth+1]];
        for ( int i=t; i<t+h; i++ ) {
            for ( int j=l; j<l+w; j++ ) {
                img[i][j]=node.color;
                openform[i][j]=1;
            }
        }
        finicore[core]+=size;
    }
    return NULL;
}

int bmpcomp( void ) {
    //Read the Bitmap info header;
    printf( "Checking the ColorDepth..." );
    fread( &infoHeader, sizeof( BITMAPINFOHEADER ), 1, pfin );
    if ( infoHeader.biBitCount==24 ) {
        printf( "    24Bit -- OK\n" );
    } else {
        printf( "    Wrong Depth. KalMatrix only accept 24Bit Depth.\nKalMatrix stopped.\n" );
        return -2;
    }
    printf( "Reading BMP..." );
    int size=infoHeader.biWidth*infoHeader.biHeight;
    int width=infoHeader.biWidth;
    int height=infoHeader.biHeight;
    int i, j;
    img=(QRGB**)malloc( sizeof( QRGB* )*height );
    for ( i=0; i<height; i++ ) {
        img[i]=(QRGB*)malloc( sizeof( QRGB )*width );
        if ( !img[i] ) {
            printf( "\nInsufficient memory space.\nKalMatrix stopped.\n" );
            return -3;
        }
    }
    openform=(char**)malloc( sizeof( char* )*height );
    for ( i=0; i<height; i++ ) {
        openform[i]=(char*)malloc( sizeof( char )*width );
        if ( !openform[i] ) {
            printf( "\nInsufficient memory space.\nKalMatrix stopped.\n" );
            return -3;
        }
        for ( j=0; j<width; j++ ) {
            openform[i][j]=0;
        }
    }
    arg arg1, arg2, arg3, arg4;
    arg1.SL=&SL1;
    arg2.SL=&SL2;
    arg3.SL=&SL3;
    arg4.SL=&SL4;
    arg1.SL->elem=(QT*)malloc( width*sizeof( QT ) );
    if ( !arg1.SL->elem ) {
        printf( "\nInsufficient memory space.\nKalMatrix stopped.\n" );
        return -3;
    }

    arg1.SL->length=0;
    arg1.SL->listsize=width;
    arg2.SL->elem=(QT*)malloc( width*sizeof( QT ) );
    if ( !arg2.SL->elem ) {
        printf( "\nInsufficient memory space.\nKalMatrix stopped.\n" );
        return -3;
    }

    arg2.SL->length=0;
    arg2.SL->listsize=width;
    arg3.SL->elem=(QT*)malloc( width*sizeof( QT ) );
    if ( !arg1.SL->elem ) {
        printf( "\nInsufficient memory space.\nKalMatrix stopped.\n" );
        return -3;
    }

    arg3.SL->length=0;
    arg3.SL->listsize=width;
    arg4.SL->elem=(QT*)malloc( width*sizeof( QT ) );
    if ( !arg4.SL->elem ) {
        printf( "\nInsufficient memory space.\nKalMatrix stopped.\n" );
        return -3;
    }

    arg4.SL->length=0;
    arg4.SL->listsize=width;
    for ( i=0; i<height; i++ )
        fread( img[i], sizeof( QRGB ), width, pfin );
    //Compressing Start.
    printf( "   OK\nCompressing Start. Quality: %3d%%\nQuad-tree Algorithm Calculating...(1 of 2)\n", quality );
    //QT Start.
    tstamp1=clock();
    total=size;
    finished=0;
    quality=( quality==100 )?100:sqrt( 100-quality )*3;
    pthread_mutex_init(&mut,NULL);
//    if ( total>0x1000000 ){
//        tstate=1;
    pthread_attr_init(&attr);
    pthread_attr_setschedpolicy(&attr, SCHED_FIFO);//sched_policy
    arg1.l=0;
    arg1.t=0;
    arg1.width=width>>1;
    arg1.height=height>>1;
    arg1.depth=0;
    arg1.core=0;
    coredepth[0]=0;
    coredepth[1]=1;
    coredepth[2]=2;
    coredepth[3]=3;
    pthread_create( &thread[0], &attr, &BMQT, (void*)&arg1 );
    arg2.l=width>>1;
    arg2.t=0;
    arg2.width=width-(width>>1);
    arg2.height=height>>1;
    arg2.depth=1;
    arg2.core=1;
    pthread_create( &thread[1], &attr, &BMQT, (void*)&arg2 );
    arg3.l=0;
    arg3.t=height>>1;
    arg3.width=width>>1;
    arg3.height=height-(height>>1);
    arg3.depth=2;
    arg3.core=2;
    pthread_create( &thread[2], &attr, &BMQT, (void*)&arg3 );
    arg4.l=width>>1;
    arg4.t=height>>1;
    arg4.width=width-(width>>1);
    arg4.height=height-(height>>1);
    arg4.depth=3;
    arg4.core=3;
    pthread_create( &thread[3], &attr, &BMQT, (void*)&arg4 );
    //BMQT( (void*)&arg4 );
    pthread_t threadcount;
    pthread_create( &threadcount, &attr, &counter, NULL );
    while ( pthread_kill(thread[0],0)==0||pthread_kill(thread[1],0)==0||pthread_kill(thread[2],0)==0||pthread_kill(thread[3],0)==0 ) {
        pthread_join( thread[0], NULL );
        pthread_join( thread[1], NULL );
        pthread_join( thread[2], NULL );
        pthread_join( thread[3], NULL );
    }
    pthread_cancel(threadcount);
    finished=finicore[0]+finicore[1]+finicore[2]+finicore[3];
    refreshprogress();
    /*    }else{
            arg arg1;
            arg1.l=0; arg1.t=0; arg1.width=width; arg1.height=height; arg1.depth=-1;
            BMQT( (void*)&arg1 );
        }*/
    //Write in file.
    tstamp2=clock();
    double dur1=(double)( tstamp2-tstamp1 )/CLOCKS_PER_SEC;
    list.length=arg1.SL->length+arg2.SL->length+arg3.SL->length+arg4.SL->length;
    printf( "\n%d Nodes Calculated in %.3fsec.\n", list.length, dur1 );
    printf( "Writing KMF Matrix Into Temporary File..." );
    fileHeader.bfType=0x4D4B; //Write Header KM
    fwrite( &fileHeader, sizeof( fileHeader ), 1, pfout );
    fwrite( &infoHeader, sizeof( infoHeader ), 1, pfout );
    fwrite( &list.length, sizeof( list.length ), 1, pfout );
    fwrite( arg1.SL->elem, sizeof( QT ), arg1.SL->length, pfout );
    fwrite( arg2.SL->elem, sizeof( QT ), arg2.SL->length, pfout );
    fwrite( arg3.SL->elem, sizeof( QT ), arg3.SL->length, pfout );
    fwrite( arg4.SL->elem, sizeof( QT ), arg4.SL->length, pfout );
    for ( i=0; i<height; i++ ) {
        for ( j=0; j<width; j++ ) {
            if ( openform[i][j]==1 ) {
                fwrite( &img[i][j], sizeof( QRGB ), 1, pfout );
            }
        }
    }
    printf( "    OK\nQT Compression Success.\n" );
    free(SL1.elem);
    free(SL2.elem);
    free(SL3.elem);
    free(SL4.elem);
    for (i=0; i<height; i++) {
        free(img[i]);
        free(openform[i]);
    }
    return 1;
}

void* counter( void* ch ) {
    pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, NULL);
    while(pthread_kill(thread[0],0)==0||pthread_kill(thread[1],0)==0||pthread_kill(thread[2],0)==0||pthread_kill(thread[3],0)==0) {
        finished=max(finished,finicore[0]+finicore[1]+finicore[2]+finicore[3]);
        pthread_testcancel();
        refreshprogress();
        pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,NULL);
        Sleep(300l);
        pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, NULL);
    }
    return ch;
}

void* BMQT( void* ch ) {
    arg* voidarg=(arg*)ch;
    int t=voidarg->t;
    int l=voidarg->l;
    int width=voidarg->width;
    int height=voidarg->height;
    int depth=voidarg->depth;
    int core=voidarg->core;
    SqList *SL=voidarg->SL;
    QRGB avr;
    short flag=0;
    int size=width*height;
    int i, j, b, r;
    b=t+height-1;
    r=l+width-1;
    //If this node is a single-pixel node, mark it in the openform, skip it.
    if ( size<=0 ) return NULL;
    if ( l<0 || l+width>infoHeader.biWidth || t<0 || t+height>infoHeader.biHeight ) return NULL;
    if ( size<=2 ) {
        for (i=t; i<=b; i++) {
            for (j=l; j<=r; j++) {
                openform[i][j]=1;
                finicore[core]++;
            }
        }
        return NULL;
    }
    //Calc PSNR when quality is below 100%--Give up PSNR since it cause mass calculation.
    if ( quality>=100 ) {
        avr.b=img[t][l].b;
        avr.g=img[t][l].g;
        avr.r=img[t][l].r;
        for( i=t; i<=b; i++ ) {
            for( j=l; j<=r; j++ ) {
                if ( img[i][j].b!=avr.b || img[i][j].g!=avr.g || img[i][j].r!=avr.r ) {
                    flag=1;
                    break;
                }
            }
            if ( flag==1 ) break;
        }
        if ( flag==0 ) {
            //Pure Color. Terminate this node. Write into struct.
            SL->elem[SL->length].depth=depth;
            SL->elem[SL->length].color=avr;
            SL->length++;
            if ( SL->length==SL->listsize ) {
                //increase size of SL->
                QT* newbase=(QT*)realloc( SL->elem, ( SL->listsize+1000 )*sizeof( QT ) );
                if ( !newbase ) {
                    printf( "\nInsufficient memory space.\nKalMatrix stopped.\n" );
                    exit( -3 );
                }
                SL->elem=newbase;
                SL->listsize+=1000;
            }
            finicore[core]+=size;
            return NULL;
        }
        flag=0;
    } else {
        //Single-Pixel-Veto.
        avr.b=img[t+(height>>1)][l+(width>>1)].b;
        avr.g=img[t+(height>>1)][l+(width>>1)].g;
        avr.r=img[t+(height>>1)][l+(width>>1)].r;
        for( i=t; i<=b; i++ ) {
            for( j=l; j<=r; j++ ) {
                if ( abs(img[i][j].b-avr.b) + abs(img[i][j].g-avr.g) + abs(img[i][j].r-avr.r)>quality ) {
                    flag=1;
                    break;
                }
            }
            if ( flag==1 ) break;
        }
        if ( flag==0 ) {
            //Pure Color. Terminate this node. Write into struct.
            SL->elem[SL->length].depth=depth;
            SL->elem[SL->length].color=avr;
            SL->length++;
            if ( SL->length==SL->listsize ) {
                //increase size of SL->
                QT* newbase=(QT*)realloc( SL->elem, ( SL->listsize+1000 )*sizeof( QT ) );
                if ( !newbase ) {
                    printf( "\nInsufficient memory space.\nKalMatrix stopped.\n" );
                    exit( -3 );
                }
                SL->elem=newbase;
                SL->listsize+=1000;
            }
            finicore[core]+=size;
            return NULL;
        }
        flag=0;
    }
    int hw, hh, nd;
    nd=( depth+1 )<<2;
    hw=width>>1;
    hh=height>>1;
    //Quad-Tree Recursion
    arg arg1, arg2, arg3, arg4;
    if (size>=16777216) {
        if (pthread_mutex_trylock(&mut)==0) {
            if (pthread_kill(thread[0],0)==0) {
                pthread_mutex_unlock(&mut);
                arg1.l=l;
                arg1.t=t;
                arg1.width=hw;
                arg1.height=hh;
                arg1.depth=nd;
                arg1.SL=SL;
                arg1.core=core;
                BMQT( (void*)&arg1 );
            } else {
                arg1.l=l;
                arg1.t=t;
                arg1.width=hw;
                arg1.height=hh;
                arg1.depth=nd;
                arg1.SL=&SL1;
                arg1.core=0;
                coredepth[0]=arg1.depth;
                pthread_create( &thread[0], &attr, &BMQT, (void*)&arg1 );
                pthread_mutex_unlock(&mut);
            }
        } else {
            arg1.l=l;
            arg1.t=t;
            arg1.width=hw;
            arg1.height=hh;
            arg1.depth=nd;
            arg1.SL=SL;
            arg1.core=core;
            BMQT( (void*)&arg1 );
        }
        if (pthread_mutex_trylock(&mut)==0) {
            if (pthread_kill(thread[1],0)==0) {
                pthread_mutex_unlock(&mut);
                arg2.l=l+hw;
                arg2.t=t;
                arg2.width=width-hw;
                arg2.height=hh;
                arg2.depth=nd+1;
                arg2.SL=SL;
                arg2.core=core;
                BMQT( (void*)&arg2 );
            } else {
                arg2.l=l+hw;
                arg2.t=t;
                arg2.width=width-hw;
                arg2.height=hh;
                arg2.depth=nd+1;
                arg2.SL=&SL2;
                arg2.core=1;
                coredepth[1]=arg2.depth;
                pthread_create( &thread[1], &attr, &BMQT, (void*)&arg2 );
                pthread_mutex_unlock(&mut);
            }
        } else {
            arg2.l=l+hw;
            arg2.t=t;
            arg2.width=width-hw;
            arg2.height=hh;
            arg2.depth=nd+1;
            arg2.SL=SL;
            arg2.core=core;
            BMQT( (void*)&arg2 );
        }
        if (pthread_mutex_trylock(&mut)==0) {
            if (pthread_kill(thread[2],0)==0) {
                pthread_mutex_unlock(&mut);
                arg3.l=l;
                arg3.t=t+hh;
                arg3.width=hw;
                arg3.height=height-hh;
                arg3.depth=nd+2;
                arg3.SL=SL;
                arg3.core=core;
                BMQT( (void*)&arg3 );
            } else {
                arg3.l=l;
                arg3.t=t+hh;
                arg3.width=hw;
                arg3.height=height-hh;
                arg3.depth=nd+2;
                arg3.SL=&SL3;
                arg3.core=2;
                coredepth[2]=arg3.depth;
                pthread_create( &thread[2], &attr, &BMQT, (void*)&arg3 );
                pthread_mutex_unlock(&mut);
            }
        } else {
            arg3.l=l;
            arg3.t=t+hh;
            arg3.width=hw;
            arg3.height=height-hh;
            arg3.depth=nd+2;
            arg3.SL=SL;
            arg3.core=core;
            BMQT( (void*)&arg3 );
        }
        if (pthread_mutex_trylock(&mut)==0) {
            if (pthread_kill(thread[3],0)==0) {
                pthread_mutex_unlock(&mut);
                arg4.l=l+hw;
                arg4.t=t+hh;
                arg4.width=width-hw;
                arg4.height=height-hh;
                arg4.depth=nd+3;
                arg4.SL=SL;
                arg4.core=core;
                BMQT( (void*)&arg4 );
            } else {
                arg4.l=l+hw;
                arg4.t=t+hh;
                arg4.width=width-hw;
                arg4.height=height-hh;
                arg4.depth=nd+3;
                arg4.SL=&SL4;
                arg4.core=3;
                coredepth[3]=arg4.depth;
                pthread_create( &thread[3], &attr, &BMQT, (void*)&arg4 );
                pthread_mutex_unlock(&mut);
            }
        } else {
            arg4.l=l+hw;
            arg4.t=t+hh;
            arg4.width=width-hw;
            arg4.height=height-hh;
            arg4.depth=nd+3;
            arg4.SL=SL;
            arg4.core=core;
            BMQT( (void*)&arg4 );
        }
    } else {
        arg1.l=l;
        arg1.t=t;
        arg1.width=hw;
        arg1.height=hh;
        arg1.depth=nd;
        arg1.SL=SL;
        arg1.core=core;
        BMQT( (void*)&arg1 );
        arg2.l=l+hw;
        arg2.t=t;
        arg2.width=width-hw;
        arg2.height=hh;
        arg2.depth=nd+1;
        arg2.SL=SL;
        arg2.core=core;
        BMQT( (void*)&arg2 );
        arg3.l=l;
        arg3.t=t+hh;
        arg3.width=hw;
        arg3.height=height-hh;
        arg3.depth=nd+2;
        arg3.SL=SL;
        arg3.core=core;
        BMQT( (void*)&arg3 );
        arg4.l=l+hw;
        arg4.t=t+hh;
        arg4.width=width-hw;
        arg4.height=height-hh;
        arg4.depth=nd+3;
        arg4.SL=SL;
        arg4.core=core;
        BMQT( (void*)&arg4 );
    }
    return NULL;
}

void refreshprogress() {
    int progress=(int)((double)finished/total*100);
    if ( progress==lastprogress2 ) return;//Prevent Lag.
    lastprogress2=progress;
    int t=progress*2/5;
    if ( lastprogress==t ) {
        putchar( '\b' );
        putchar( '\b' );
        putchar( '\b' );
        putchar( '\b' );
        printf( "%3d%%", lastprogress2 );
        return;
    }
    lastprogress=t;
    int j=0;
    printf( "\r[" );
    for ( j=0; j<t; j++ )
        putchar( '=' );
    putchar( '>' );
    for ( j=1; j<=39-t; j++ )
        putchar( '.' );
    putchar( ']' );
    printf( "  %3d%%", lastprogress2 );
    //Notify: Always put a "\n" when progress is completed.
}
